﻿using System;
using normalize = KeyWordSearch.Normalization;

namespace KeyWordSearch.ProcessTree
{
	internal sealed class ContainCheckProcess:TerminalNode
	{
		public ContainCheckProcess(NonTerminalNode parent, string checkPhrase, InspectionField field, InspectionTarget target)
			: base(parent)
		{
			if (parent == null)
			{
				throw new ArgumentNullException("parent");
			}

			if (checkPhrase == null)
			{
				throw new ArgumentNullException("checkPhrase");
			}

			if (target == InspectionTarget.None)
			{
				throw new ArgumentOutOfRangeException("target");
			}

			if (field == InspectionField.None)
			{
				throw new ArgumentOutOfRangeException("field");
			}

			var normalize = normalize::Normalizer.Normalize(checkPhrase);

			switch (target)
			{
				case InspectionTarget.AlphaNumericNormalized:
					this.CheckPhrase = normalize.AlphaNumeric;
					break;

				case InspectionTarget.BothNormalized:
					this.CheckPhrase = normalize.Both;
					break;

				case InspectionTarget.KanaNormalized:
					this.CheckPhrase = normalize.Kana;
					break;

				case InspectionTarget.NFC:
					this.CheckPhrase = normalize.NFC;
					break;

				default:
					throw new ProcessInconsistencyException("想定外のInspectionTargetです");

			}

			this.Target = target;
			this.Field = field;
		}


		public string CheckPhrase
		{
			get;
			private set;
		}

		public InspectionField Field
		{
			get;
			private set;
		}

		public InspectionTarget Target
		{
			get;
			private set;
		}

		public override ExecuteResult Execute(normalize::LiveProgramNormalizationResult inspectionTarget)
		{
			int result = -1;
			string tmp = null;

			if ((Field & InspectionField.CasterName) == InspectionField.CasterName)
			{
				tmp = GetString(inspectionTarget.CasterName);
				if (tmp != null)
				{
					result = tmp.IndexOf(CheckPhrase);
				}
			}
			if ((Field & InspectionField.Description) == InspectionField.Description && result == -1)
			{
				tmp = GetString(inspectionTarget.Description);
				if (tmp != null)
				{
					result = tmp.IndexOf(CheckPhrase);
				}
			}
			if ((Field & InspectionField.StationName) == InspectionField.StationName && result == -1)
			{
				tmp = GetString(inspectionTarget.StationName);
				if (tmp != null)
				{
					result = tmp.IndexOf(CheckPhrase);
				}
			}
			if ((Field & InspectionField.Title) == InspectionField.Title && result == -1)
			{
				tmp = GetString(inspectionTarget.Title);
				if (tmp != null)
				{
					result = tmp.IndexOf(CheckPhrase);
				}
			}


			if (result == -1)
			{
				return new ExecuteResult(false);
			}
			else
			{
				ExecuteResult ret = new ExecuteResult(true);
				ret.ResultElements.Add(new ExecuteResultElement() 
				{ Source = tmp, Index = result, Length = CheckPhrase.Length, Field = this.Field, Target = this.Target, ReportCause = true });

				return ret;
			}
	
		}

		private string GetString(normalize::NormalizationResult result)
		{
			switch (Target)
			{
				case InspectionTarget.AlphaNumericNormalized:
					return result.AlphaNumeric;

				case InspectionTarget.BothNormalized:
					return result.Both;

				case InspectionTarget.KanaNormalized:
					return result.Kana;

				case InspectionTarget.NFC:
					return result.NFC;

				default:
					throw new ProcessInconsistencyException("想定外のInspectionTargetです");
			}
		}
	}
}
